using System;
using System.Collections.Generic;
using System.Text;
using org.qsoft.rpcfx.common;
using org.qsoft.rpcfx.util;
using System.Collections;
using System.Reflection;

namespace nrpcfx.org.qsoft.rpcfx.bean
{
    public abstract class AbstractObjectWriter : IObjectWriter
    {

        private IConvertType _iConvertType = new QConvertType();

        public IConvertType iConvertType
        {
            get { return _iConvertType; }
            set { _iConvertType = value; }
        }

        

        public void write(object obj, string name)
        {
            if (obj == null) return;

            Type type = obj.GetType();

            if (TypeUtil.isCommonType(type))
            {
                writeNode( obj, name);
            }
            else if (type.IsArray)
            {
                writeArray(obj, name);     
            }
            else if (typeof(IDictionary).IsAssignableFrom(type))
            {
                writeMap(obj, name);
            }
            else if (typeof(IList).IsAssignableFrom(type))
            {
                writeList(obj, name);
            }
            else
            {
                writeStart(name,type.FullName);

                PropertyInfo[] propertyInfos = type.GetProperties();
                foreach (PropertyInfo pi in propertyInfos)
                {
                    write( pi.GetValue(obj,null), pi.Name);
                }

                writeEnd();
            }
        }

        public void writeArray(object obj, string name)
        {
            Type type = obj.GetType();
            Type elementType = type.GetElementType();
            Array array = obj as Array;

            string arrayFlag = _iConvertType.convertType(elementType);
            if (arrayFlag == null)
            {
                arrayFlag = elementType.FullName;
            }
            arrayFlag = "array@" + array.Rank.ToString() + "@" + arrayFlag;

            this.writeStart(name,arrayFlag);
            foreach (object o in array)
            {
                write(o,"item");
            }
            this.writeEnd();
        }

        public void writeList(object obj, string name)
        {
            Type type = obj.GetType();
            ICollection coll = obj as ICollection;
            
            string arrayFlag = "list@" + type.FullName;

            this.writeStart(name, arrayFlag);
            IEnumerator ie = coll.GetEnumerator();
            while(ie.MoveNext()){
                write(ie.Current, "item");
            }
            this.writeEnd();

        }

        public void writeMap(object obj, string name)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public abstract void writeNode(object obj, string name);

        public abstract void writeStart(string name, string type);

        public abstract void writeEnd();

        public abstract string Serialize(object target);

    }
}
